/*
 * Copyright (c) 2024 Huawei Technologies Co.,Ltd.
 *
 * openGauss is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 * http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 * -------------------------------------------------------------------------
 *
 * htap_internal.h
 * API for the HTAP Delta
 *
 * IDENTIFICATION
 * src/include/storage/htap/htap_internal.h
 *
 * -------------------------------------------------------------------------
 */

#ifndef HTAP_INTERNAL_H
#define HTAP_INTERNAL_H

#include <unordered_map>
#include <map>
#include "nodes/parsenodes_common.h"
#include "nodes/parsenodes.h"
#include "row.h"
#include "utils/numeric.h"
#include "utils/numeric_gs.h"

namespace htap {

typedef struct HTAPCTID {
    HTAPCTID(uint16 bi_hi, uint16 bi_lo, uint16 ip_posid, uint64_t status)
    {
        m_u.m_rowId = 0;
        m_u.m_ctid.m_offset = 0;
        m_u.m_ctid.m_reserve = 0;

        m_u.m_ctid.m_blId.m_bi_hi = bi_hi;
        m_u.m_ctid.m_blId.m_bi_lo = bi_lo;
        m_u.m_ctid.m_offset = ip_posid;
        m_u.m_ctid.m_status = status;
    }

    union {
        uint64_t m_rowId;
        MOT::RowCTID m_ctid;
    } m_u;
    uint64_t GetCTIDKey()
    {
        return htobe64(m_u.m_rowId & ROW_CTID_MASK);
    }

    uint64_t GetCTIDFlat() const
    {
        return (m_u.m_rowId & ROW_CTID_MASK);
    }
} HTAPCTID;

class HTAPAdaptor {
public:
    /**
     * @brief Initialize MOT engine singleton.
     */
    static void Init();

    /**
     * @brief Destroy MOT engine singleton.
     */
    static void Destroy();

    /** @var MOT engine singleton */
    static MOT::MOTEngine* m_engine;

    /** @var indicates if MOT engine initialized */
    static bool m_initialized;

    /** @var indicates if MOT callbacks has been installed */
    static bool m_callbacks_initialized;

    static RC CreateTable(Oid parent_oid, Oid rel_oid);

    static RC DropTable(Oid rel_oid, std::unordered_map<Oid, RelFileNode> **out_oid_del_info);
    static MOT::RC ValidateCommit();
    static void RecordCommit(uint64_t csn);
    static MOT::RC Commit(uint64_t csn);
    static bool IsTxnWriteSetEmpty();
    static void EndTransaction();
    static void Rollback();
    static MOT::RC Prepare();
    static void CommitPrepared(uint64_t csn);
    static void RollbackPrepared();
    static RC TruncateTable(Oid rel_oid, std::unordered_map<Oid, RelFileNode> **out_oid_del_info);
    static RC Truncate(Oid rel_oid);
    static RC QueryDelta(Oid relationId, uint64_t &rowCount, uint64_t &newRowCount, uint64_t &memSize);

    static RC TableModify(Oid rel_oid, ItemPointer ctid, TupleTableSlot *slot);
    static RC TableInsert(Oid rel_oid, ItemPointer ctid, TupleTableSlot *slot);
    static RC TableDelete(Oid rel_oid, ItemPointer ctid, bool fromUpd);

    static MOT::RC PackRow(TupleTableSlot *slot, MOT::Table *table, uint8_t *attrs_used, uint8_t *destRow);

    static MOT::Table *getCurrentMOTTable(Oid rel_oid);

    static uint64_t GetCtid(ItemPointer ctid)
    {
        // Ordering the fields to make incremental CTID
        // we put the most varying fields in the lower bytes, and the zero byte in the upper byte
        uint64_t flat_ctid = (((uint64_t)ctid->ip_blkid.bi_hi) << 32) | (((uint64_t)ctid->ip_blkid.bi_lo) << 16) |
                             ((uint64_t)ctid->ip_posid);
        return flat_ctid;
    }

    static void FillCtid(uint64_t flat_ctid, ItemPointer ctid)
    {
        ctid->ip_blkid.bi_hi = (flat_ctid >> 32) & 0xFFFF;
        ctid->ip_blkid.bi_lo = (flat_ctid >> 16) & 0xFFFF;
        ctid->ip_posid = flat_ctid & 0xFFFF;
    }

    /**
     * @brief Performs conversion of DECIMAL PG type to MOT type.
     * @param n PG PGNumericToMOT @param[out] d MOT value
     */
    inline static void PGNumericToMOT(const Numeric n, MOT::DecimalSt& d)
    {
        int sign = NUMERIC_SIGN(n);

        d.m_hdr.m_flags = 0;
        d.m_hdr.m_flags |= (sign == NUMERIC_POS
                                ? DECIMAL_POSITIVE
                                : (sign == NUMERIC_NEG ? DECIMAL_NEGATIVE : ((sign == NUMERIC_NAN) ? DECIMAL_NAN : 0)));
        d.m_hdr.m_ndigits = NUMERIC_NDIGITS(n);
        d.m_hdr.m_scale = NUMERIC_DSCALE(n);
        d.m_hdr.m_weight = NUMERIC_WEIGHT(n);
        d.m_round = 0;
        if (d.m_hdr.m_ndigits > 0) {
            errno_t erc = memcpy_s(d.m_digits,
                                   DECIMAL_MAX_SIZE - sizeof(MOT::DecimalSt),
                                   (void*)NUMERIC_DIGITS(n),
                                   d.m_hdr.m_ndigits * sizeof(NumericDigit));
            securec_check(erc, "\0", "\0");
        }
    }

    static void DatumToMOT(MOT::Column* col, Datum datum, Oid type, uint8_t* data);

    static void MOTToDatum1(MOT::Column *col, int2 attlen, Oid type, int deltaColIdx, uint8_t *data, bool *isNull,
                     ScalarVector *colVec, uint32_t recIdx);

    static void MOTToDatum1(MOT::Column *col, int2 attlen, Oid type, int deltaColIdx, uint8_t *data, bool *isNull,
                     Datum *value_out, size_t *lenOut);
};
} // namespace htap
#endif // HTAP_INTERNAL_H
